home *** CD-ROM | disk | FTP | other *** search
- /*-----------------------------------------------------------------------------
-
- Generic LaserWriter.c
-
- This part of the driver demonstrates how to implement custom
- old-API dialogs for a PostScript driver.
-
- 12/18/93 - dmh - Removed IIg-dependencies for b3.
- 9/13/93 - dmh - Updated for the b2 seed.
- 9/14/93 - dmh - Disabled the PostScript log which was created in
- the Extensions folder.
- 2/11/94 - dmh - Added custom old-API dialogs.
- 3/08/94 - lll - Fixed DriverConvertPrintRecordTo so that Orientation is handled correctly
- 4/20/94 - dmh - Aaaaah! Forgotten style dialog raises havok. News at 11.
- 6/20/94 - dmh - Removed the PS file log code, for clarity.
- 8/28/94 - dmh - Finalized for SDK.
- 6/14/96 - cn - Updated to support Universal Interfaces 2.1.
-
- © 1991-1996 Apple Computer Inc.
-
- -----------------------------------------------------------------------------*/
-
- #include <GXPrinterDrivers.h>
- #include <GXExceptions.h>
- #include <TextUtils.h>
- #include <Packages.h>
- #include <Resources.h>
- #include <Errors.h>
- #include <StandardFile.h>
-
- #define kDeviceByte (char) 0x88 /* Our wDev ID */
-
- #define kJob_CopiesEditText 5
- #define kJob_AllPagesRadio 7
- #define kJob_FromPageRadio 8
- #define kJob_FromPageEditText 9
- #define kJob_ToPageEditText 11
- #define kJob_AutoFeedRadio 12
- #define kJob_ManualFeedRadio 13
- #define kJob_PrintToDiskCheckBox 15
- #define kJob_lineFrill_1 16
- #define kJob_lineFrill_2 17
-
- #define kStl_lineFrill_1 4
- #define kStl_lineFrill_2 5
-
- extern long A5Size (void);
- extern void A5Init (void *);
-
- void InitJobDialogControls(DialogPtr theDialog, THPrint thePrintHdl);
- OSErr PrepForFileWriting(void);
- pascal void DriverJobItemHandler(DialogPtr theDialog, short item);
- pascal Boolean DriverJobFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit);
- void ToggleControl(void **itemH);
- void SetTheControlValue(void **itemH, short desiredValue);
- void UpdateJobDlgPrintRec(DialogPtr theDialog);
- OSErr StoreJobCollectionItem(void *collectItem, long collectSize,
- OSType collectType, long collectID);
-
- long GetCurrentA5(void) = 0x200D; // move.l a5, d0
-
-
- // A structure for our context data.
-
- typedef struct MyContextDataRec {
- long appA5;
- Boolean inStyleDialog;
- } MyContextDataRec, *MyContextDataPtr, **MyContextDataHdl;
-
-
-
- /* ______________________________________________________________
-
- DriverInitialize -
-
- This routine is a total override of the gxInitialize
- message. In here, we store the application's A5 reference
- for later, and set up our driver's A5 world, so we can
- access global data.
-
- WHY THIS IS IMPORTANT:
-
- If you do not have the application's A5 reference, you won't
- be able to support application callbacks, which occur when
- you totally (and properly) override PrDlgMain. If you're
- going to perform a total override of PrDlgMain, you need
- the app's A5 value. This is probably the best place to get
- it. Note that we get and store the A5 reference in our
- instance context BEFORE calling NewMessageGlobals. Once
- NewMessageGlobals is called, the app's A5 reference is
- replaced with ours.
-
- ______________________________________________________________ */
-
- OSErr DriverInitialize(void)
- {
- OSErr err;
- MyContextDataHdl contextData;
-
- contextData = (MyContextDataHdl) NewHandleSys(sizeof(MyContextDataRec));
- nrequire(err = MemError(), NewHandleSys_Failed);
-
- (*contextData)->appA5 = GetCurrentA5();
- (*contextData)->inStyleDialog = false;
- SetMessageHandlerInstanceContext(contextData);
-
- err = NewMessageGlobals(A5Size(), A5Init);
-
- NewHandleSys_Failed:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverShutDown -
-
- This routine is a total override of the gxShutDown
- message.
-
- WHY THIS IS IMPORTANT:
-
- It cleans up after our DriverInitialize override.
-
- ______________________________________________________________ */
-
- OSErr DriverShutDown(void)
- {
- MyContextDataHdl contextData;
-
- contextData = GetMessageHandlerInstanceContext();
-
- if (contextData != nil)
- DisposHandle((Handle) contextData);
-
- DisposeMessageGlobals();
- return noErr;
- }
-
-
- /* ______________________________________________________________
-
- DriverPrDlgMain -
-
- This routine is a total override of the gxPrDlgMain message in
- the Job dialog case, and a partial override in the Style
- dialog case. In here, we perform displaying and handling of
- the old-API print (Job and Style) dialogs.
-
- WHY THIS IS IMPORTANT:
-
- If you need to customize the old-API dialogs for a PostScript
- driver, you cannot simply add a 'dctl' and 'DITL' resource
- like you can for a raster or vector driver. The default
- PostScript implementation will ignore your resources. Also,
- because of everything the default PostScript implementation
- does with its own dctl behind the scenes, you cannot partially
- override this message, switch in your dialog somehow and
- live to tell about it.
-
- You must completely override this message if you're doing
- custom old-API dialogs for a PostScript driver (As in the Job
- dialog case for this driver. And, you need the application's
- A5 reference to pull this off. See the DriverInitialize routine
- above for details on getting that reference.
-
- ______________________________________________________________ */
-
- OSErr DriverPrDlgMain(THPrint hPrint, PDlgInitProcPtr pDlgInit,
- Boolean *okPressed)
- {
- OSErr err = noErr;
- TPPrDlg prDlgPtr;
- GrafPtr oldPort;
- short itemHit;
- long oldA5, appA5;
- MyContextDataHdl contextData;
-
- /*
- Retrieve the data we stored in our instance context.
- This data contains a reference to the app's A5 world,
- and a boolean indicating wether we're putting up the
- Style or Job dialogs. If we're being called for the
- Style dialog, simply forward the message and return.
- That's because this driver doesn't modify the default
- PS style dialog.
- */
-
- contextData = GetMessageHandlerInstanceContext();
-
- if ((*contextData)->inStyleDialog)
- {
- err = Forward_GXPrDlgMain(hPrint, pDlgInit, okPressed);
- nrequire(true, ClearContextFlag);
- }
-
-
- /*
- Retrieve the application's A5 reference that we stored
- in our instance context. If it's valid (non-nil),
- save our A5, switch in the app's, and call the initProc to
- get the print dialog pointer.
-
- If the application added any items to our dialog, it will
- do some initialization here, and may need it's A5 to be
- valid to do so. After we return, restore our A5 value so
- that we can access our globals and so forth.
- */
-
- appA5 = (*contextData)->appA5;
-
- if (appA5)
- oldA5 = SetA5(appA5);
-
- prDlgPtr = (*pDlgInit)(hPrint);
-
- if (appA5)
- SetA5(oldA5);
-
- require(prDlgPtr, DialogInit);
-
-
- /*
- Now that we have the print dialog, save the current port,
- and show the dialog.
- */
-
- GetPort(&oldPort);
- ShowWindow((WindowPtr) prDlgPtr);
-
-
- /*
- Here's the guts of this routine. We simply use ModalDialog
- to handle things. Notice that we restore the app's A5
- register around the ModalDialog procedure. Again, this is
- a likely place for an app to handle appended dialog items,
- and it may require a valid A5 to do so.
-
- Take a look at DriverPrJobInit or DriverPrStlInit to see
- how we set up both the filterProc and the itemProc before
- we ever get here. You may be wondering how an application
- could get control since we're doing that. The app would
- replace our filter and item procs with its own, and then
- pass control back to us as needed (for handling our items).
-
- Anyway, we keep looping until the fDone flag is set.
- */
-
- do
- {
- SetPort((GrafPtr) prDlgPtr);
-
- if (appA5)
- oldA5 = SetA5(appA5);
-
- ModalDialog(prDlgPtr->pFltrProc, &itemHit);
- prDlgPtr->pItemProc((DialogPtr) prDlgPtr, itemHit);
-
- if (appA5)
- SetA5(oldA5);
-
- } while (!prDlgPtr->fDone);
-
- *okPressed = prDlgPtr->fDoIt;
- SetPort(oldPort);
-
- /*
- We're all done with the grunt work. Now clean up after
- ourselves and validate the dialog if the user pressed OK.
- Finally, clear the idle proc to make sure that an old
- one that was saved in the document doesn't get used by
- mistake!
- */
-
- CloseDialog((DialogPtr) prDlgPtr);
- DisposHandle(((DialogPeek) prDlgPtr)->items);
- DisposePtr((Ptr) prDlgPtr);
-
- /*
- If the user pressed OK, call PrValidate.
- */
-
- if (*okPressed)
- {
- PrValidate(hPrint);
- (*hPrint)->prJob.pIdleProc = nil;
- }
-
- ClearContextFlag:
- contextData = GetMessageHandlerInstanceContext();
- (*contextData)->inStyleDialog = false;
- SetMessageHandlerInstanceContext(contextData);
-
- DialogInit:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverPrStlInit -
-
- This routine is a partial override for the gxPrStlInit message.
-
- WHY THIS IS IMPORTANT:
-
- This is where we set our flag that tells PrDlgMain that we're
- putting up the Style dialog.
-
- ______________________________________________________________ */
-
- OSErr DriverPrStlInit(THPrint aPrintHdl, TPPrDlg *aPrDlg)
- {
- MyContextDataHdl contextData;
-
- contextData = GetMessageHandlerInstanceContext();
- (*contextData)->inStyleDialog = true;
- SetMessageHandlerInstanceContext(contextData);
-
- return Forward_GXPrStlInit(aPrintHdl, aPrDlg);
- }
-
-
- /* ______________________________________________________________
-
- DriverPrJobInit -
-
- This routine is a total override for the gxPrJobInit message.
- In here, we create our print dialog pointer, and initialize
- it and the print handle as we see fit.
-
- WHY THIS IS IMPORTANT:
-
- This is where we install our ModalDialog filter proc and our
- job item handler.
-
- You must completely override this message if you're changing
- the default old-API dialogs in any way. If you try to perform
- a partial override, the default PS implementation is going to
- give you a good swift kick.
-
- ______________________________________________________________ */
-
- OSErr DriverPrJobInit(THPrint aPrintHdl, TPPrDlg *aPrDlg)
- {
- OSErr err = noErr;
- short oldResFile = CurResFile();
- MyContextDataHdl contextData;
-
- /*
- Indicate to our PrDlgMain override that we are displaying
- the Print dialog.
- */
-
- contextData = GetMessageHandlerInstanceContext();
- (*contextData)->inStyleDialog = false;
- SetMessageHandlerInstanceContext(contextData);
-
-
- /*
- Validate our print record, then create our dialog pointer.
- */
-
- PrValidate(aPrintHdl);
- *aPrDlg = (TPPrDlg) NewPtrClear(sizeof(TPrDlg));
- require_action(*aPrDlg, NewPtrClear_Failed, err = MemError(););
-
-
- /*
- This next line forces manual feed mode off for our driver.
- The rest is standard print dialog setup stuff.
- */
-
- (*aPrintHdl)->prStl.feed = 2;
-
- (*aPrDlg)->pFltrProc = (ModalFilterProcPtr) DriverJobFilterProc;
- (*aPrDlg)->pItemProc = (PItemProcPtr) DriverJobItemHandler;
- (*aPrDlg)->hPrintUsr = aPrintHdl;
- (*aPrDlg)->fDoIt = false;
- (*aPrDlg)->fDone = false;
-
-
- /*
- Load our dialog, using the dialog pointer we just created.
- Initialize our dialog's controls so they reflect what's
- currently in our print record. You need the drivers resfile
- or the pict in the print dialog will be scrunged in some apps
- */
-
- UseResFile(GXGetMessageHandlerResFile());
- GetNewDialog(gxJobDialogResID, *aPrDlg, (WindowPtr) -1);
- InitJobDialogControls((DialogPtr) *aPrDlg, aPrintHdl);
-
- UseResFile(oldResFile);
-
- NewPtrClear_Failed:
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverJobFilterProc -
-
- This routine is our ModalDialog filter proc for our Print
- dialog. It gets called during the PrDlgMain cycle.
-
- WHY THIS IS IMPORTANT:
-
- This is where we can handle update events for user items, and
- that sort of thing.
-
- ______________________________________________________________ */
-
- pascal Boolean DriverJobFilterProc(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
- {
- short itemKind;
- Handle itemHdl;
- Rect itemRect;
-
- #pragma unused(itemHit);
-
- /*
- If there's an update event, draw a border around the default
- button, and draw our dialog's line frills.
- */
-
- switch (theEvent->what)
- {
- case updateEvt:
-
- SetPort(theDialog);
- GetDItem(theDialog, ok, &itemKind, &itemHdl, &itemRect);
- PenSize(3, 3);
- InsetRect(&itemRect, -4, -4);
- FrameRoundRect(&itemRect, 16, 16);
- PenSize(1, 1);
-
- GetDItem(theDialog, kJob_lineFrill_1, &itemKind, &itemHdl, &itemRect);
- MoveTo(itemRect.left, itemRect.top);
- LineTo(itemRect.right, itemRect.top);
- GetDItem(theDialog, kJob_lineFrill_2, &itemKind, &itemHdl, &itemRect);
- MoveTo(itemRect.left, itemRect.top);
- LineTo(itemRect.right, itemRect.top);
- break;
- }
-
- return false;
- }
-
-
- /* ______________________________________________________________
-
- DriverJobItemHandler -
-
- This routine handles item hits in our job dialog. It is
- installed in the print dialog by DriverPrJobInit, and will be
- called during the PrDlgMain cycle.
-
- WHY THIS IS IMPORTANT:
-
- This is the routine that handles all hits in our Print dialog.
-
- ______________________________________________________________ */
-
- pascal void DriverJobItemHandler(DialogPtr theDialog, short item)
- {
- OSErr err = noErr;
- TPPrDlg thePrDlg = (TPPrDlg) theDialog;
- short itemKind;
- Handle itemHdl;
- Rect itemRect;
-
- switch (item)
- {
- /*
- Was OK pressed? See if we're printing to disk. If so, prompt
- the user for a location. If they cancel, continue with the print
- dialog. Otherwise, update the print record to reflect the current
- dialog settings, and signal that we're done and we're going to
- "do it."
-
- Note that PrepForFileWriting adds our "print to file" collection
- items to the current job for us.
- */
- case ok:
- GetDItem(theDialog, kJob_PrintToDiskCheckBox, &itemKind, &itemHdl, &itemRect);
- if (GetCtlValue((ControlHandle) itemHdl) != 0)
- err = PrepForFileWriting();
-
- if (!err)
- {
- thePrDlg->fDoIt = true;
- thePrDlg->fDone = true;
- UpdateJobDlgPrintRec(theDialog);
- }
- break;
- /*
- Was Cancel pressed? We're done but we're not "doing it."
- */
- case cancel:
- thePrDlg->fDoIt = false;
- thePrDlg->fDone = true;
- break;
- /*
- Were the "All" or "From" page radio buttons pressed? Select them
- appropriately.
- */
- case kJob_AllPagesRadio:
- case kJob_FromPageRadio:
- GetDItem(theDialog, kJob_AllPagesRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, (item == kJob_AllPagesRadio)? 1: 0);
- GetDItem(theDialog, kJob_FromPageRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, (item == kJob_FromPageRadio)? 1: 0);
- break;
- /*
- Were the "From" or "To" editText items hit? Select the "From"
- radio button, and deselect the "All" radio button.
- */
- case kJob_FromPageEditText:
- case kJob_ToPageEditText:
- GetDItem(theDialog, kJob_AllPagesRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, 0);
- GetDItem(theDialog, kJob_FromPageRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, 1);
- break;
- /*
- Were the "Automatic" or "Manual" feed radio buttons hit? Select
- them appropriately.
- */
- case kJob_AutoFeedRadio:
- case kJob_ManualFeedRadio:
- GetDItem(theDialog, kJob_AutoFeedRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, (item == kJob_AutoFeedRadio)? 1: 0);
- GetDItem(theDialog, kJob_ManualFeedRadio, &itemKind, &itemHdl, &itemRect);
- SetTheControlValue((void **) itemHdl, (item == kJob_ManualFeedRadio)? 1: 0);
- break;
- /*
- Was the "Print to disk" checkBox hit? Toggle its value.
- */
- case kJob_PrintToDiskCheckBox:
- GetDItem(theDialog, kJob_PrintToDiskCheckBox, &itemKind, &itemHdl, &itemRect);
- ToggleControl((void **) itemHdl);
- break;
- }
- }
-
-
- /* ______________________________________________________________
-
- UpdateJobDlgPrintRec -
-
- This routine updates the job dialog's print record so that
- it reflects the current dialog settings. This routine is only
- called when a user "OKs" the job dialog. It is the opposite of
- InitJobDialogControls.
-
- WHY THIS IS IMPORTANT:
-
- This is how we transfer all the button clicks we handled in
- DriverJobItemHandler into settings in the driver's print
- record.
-
- ______________________________________________________________ */
-
- void UpdateJobDlgPrintRec(DialogPtr theDialog)
- {
- TPPrDlg thePrDlg = (TPPrDlg) theDialog;
- THPrint printRecHdl = thePrDlg->hPrintUsr;
- short itemKind, ctlVal;
- long numCopies, fstPage, lstPage;
- Handle itemHdl;
- Rect itemRect;
- Str255 pStr;
-
- /*
- Get the value of the "All pages" radio button. If it's set,
- make our page range 1 through 9999. Otherwise, use the user's
- range, (from the "From" and "To" editText fields. Also do a
- bit of sanity checking on the user's values.
- */
-
- GetDItem(theDialog, kJob_AllPagesRadio, &itemKind, &itemHdl, &itemRect);
- ctlVal = GetCtlValue((ControlHandle) itemHdl);
- if (ctlVal != 0)
- {
- (*printRecHdl)->prJob.iFstPage = 1;
- (*printRecHdl)->prJob.iLstPage = 9999;
- }
- else
- {
- GetDItem(theDialog, kJob_FromPageEditText, &itemKind, &itemHdl, &itemRect);
- GetIText(itemHdl, pStr);
- StringToNum(pStr, &fstPage);
- GetDItem(theDialog, kJob_ToPageEditText, &itemKind, &itemHdl, &itemRect);
- GetIText(itemHdl, pStr);
- StringToNum(pStr, &lstPage);
-
- fstPage = (fstPage < 1)? 1: fstPage;
- fstPage = (fstPage > 9999)? 9999: fstPage;
- lstPage = (lstPage < 1)? 1: lstPage;
- lstPage = (lstPage > 9999)? 9999: lstPage;
- lstPage = (lstPage < fstPage)? fstPage: lstPage;
-
- (*printRecHdl)->prJob.iFstPage = fstPage;
- (*printRecHdl)->prJob.iLstPage = lstPage;
- }
-
- /*
- Get the number of copies and store it in the print record
- where our driver likes it.
- */
-
- GetDItem(theDialog, kJob_CopiesEditText, &itemKind, &itemHdl, &itemRect);
- GetIText(itemHdl, pStr);
- StringToNum(pStr, &numCopies);
- (*printRecHdl)->prXInfo.iRowBytes = (numCopies > 0)? numCopies:1;
-
-
- /*
- Get the "print to disk" value, and store it in the print record
- where our driver likes it. Yes, this looks a bit weird, but 120
- bytes only go so far.
-
- Note that we disable manual feed if we're printing to disk.
- If we're not printing to disk, see if we're manually feeding,
- and store that info as our driver likes it.
- */
-
- GetDItem(theDialog, kJob_PrintToDiskCheckBox, &itemKind, &itemHdl, &itemRect);
- ctlVal = GetCtlValue((ControlHandle) itemHdl);
- (*printRecHdl)->prXInfo.bUlOffset = (ctlVal != 0)? 1 :0;
-
- if (ctlVal == 0)
- {
- GetDItem(theDialog, kJob_ManualFeedRadio, &itemKind, &itemHdl, &itemRect);
- ctlVal = GetCtlValue((ControlHandle) itemHdl);
- (*printRecHdl)->prStl.feed = (ctlVal != 0)? 3: 2;
- }
- else
- (*printRecHdl)->prStl.feed = 2;
- }
-
-
- /* ______________________________________________________________
-
- InitJobDialogControls -
-
- This routine initializes the controls of our dialog so that
- they reflect what's in the passed print record. This routine
- is only called when the job dialog is about to be displayed.
- It is the opposite of UpdateJobDlgPrintRec.
-
- WHY THIS IS IMPORTANT:
-
- This is where we synchronize the job dialog with what's in
- our print record.
-
- ______________________________________________________________ */
-
- void InitJobDialogControls(DialogPtr theDialog, THPrint thePrintHdl)
- {
- short itemKind;
- Handle itemHdl1, itemHdl2, itemHdl3, itemHdl4;
- Rect itemRect;
- TPrint *printRecPtr;
- Str255 pStr;
- char oldState;
-
- /*
- Lock down the print handle so we can treat it as a pointer.
- Save the lock state so that we can restore it when we exit.
- */
-
- oldState = HGetState((Handle) thePrintHdl);
- HLock((Handle) thePrintHdl);
- printRecPtr = *thePrintHdl;
-
-
- /*
- Set up the "From… To…" editText items, and enable the appropriate
- radio button. We only enable the "All pages" radio button if
- pages 1 through 9999 are selected.
- */
-
- GetDItem(theDialog, kJob_AllPagesRadio, &itemKind, &itemHdl1, &itemRect);
- GetDItem(theDialog, kJob_FromPageRadio, &itemKind, &itemHdl2, &itemRect);
- GetDItem(theDialog, kJob_FromPageEditText, &itemKind, &itemHdl3, &itemRect);
- GetDItem(theDialog, kJob_ToPageEditText, &itemKind, &itemHdl4, &itemRect);
-
- if ((printRecPtr->prJob.iFstPage == 1) && (printRecPtr->prJob.iLstPage == 9999))
- {
- SetTheControlValue((void **) itemHdl1, 1); // Printing all pages
- SetTheControlValue((void **) itemHdl2, 0);
- SetIText(itemHdl3, "\p");
- SetIText(itemHdl4, "\p");
- }
- else
- {
- SetTheControlValue((void **) itemHdl1, 0); // Printing "From… To…"
- SetTheControlValue((void **) itemHdl2, 1);
- NumToString(printRecPtr->prJob.iFstPage, pStr);
- SetIText(itemHdl3, pStr);
- NumToString(printRecPtr->prJob.iLstPage, pStr);
- SetIText(itemHdl4, pStr);
- }
-
- /*
- Set up the number of copies editText item. Our driver stores this
- value in the prXInfo.iRowBytes field of the print record.
- */
-
- GetDItem(theDialog, kJob_CopiesEditText, &itemKind, &itemHdl1, &itemRect);
- NumToString(printRecPtr->prXInfo.iRowBytes, pStr);
- SetIText(itemHdl1, pStr);
-
-
- /*
- Set up the "Automatic" or "Manual" Feed radio buttons. Our
- driver stores this information in the prStl.feed field of
- the print record.
- */
-
- GetDItem(theDialog, kJob_AutoFeedRadio, &itemKind, &itemHdl1, &itemRect);
- SetTheControlValue((void **) itemHdl1, (printRecPtr->prStl.feed == 3)? 0: 1);
- GetDItem(theDialog, kJob_ManualFeedRadio, &itemKind, &itemHdl1, &itemRect);
- SetTheControlValue((void **) itemHdl1, (printRecPtr->prStl.feed == 3)? 1: 0);
-
-
- /*
- Set up the "Print to disk" checkBox. Our driver stores this
- information in the prXInfo.bUlOffset field of the print record.
- Restore the print handle's lock status as we exit this routine.
- */
-
- GetDItem(theDialog, kJob_PrintToDiskCheckBox, &itemKind, &itemHdl1, &itemRect);
- SetTheControlValue((void **) itemHdl1, (printRecPtr->prXInfo.bUlOffset == 0)? 0: 1);
-
- HSetState((Handle) thePrintHdl, oldState);
- }
-
-
- /* ______________________________________________________________
-
- PrepForFileWriting -
-
- This routine asks the user where to save a PostScript file.
- If the user doesn't cancel, it saves the appropriate
- collection items in the current job to make printing to a
- file happen.
-
- WHY THIS IS IMPORTANT:
-
- The default PostScript implementation of PrJobInit installs
- an item handler proc for the default old-API dialogs. The
- "print to file" StandardFile dialog is handled in that item
- handling proc. Since we completely override gxPrJobInit, the
- default "print to file" file dialog code is never used. You
- must supply this routine if you completely override PrJobInit,
- and you want to print to PostScript (or other) files.
-
- For simplicity, this file dialog only saves in one format--
- PostScript® with no fonts. It's a straightforward
- CustomPutFile exercise to reproduce the default dialog if you
- so desire.
-
- ______________________________________________________________ */
-
- OSErr PrepForFileWriting()
- {
- OSErr err = noErr;
- gxFileDestinationInfo destInfo;
- gxFileFormatInfo destFFmt;
- gxFileLocationInfo fileLocInfo;
- gxFileFontsInfo fontsInfo;
- StandardFileReply putReply;
-
- /*
- Display a StandardPutFile dialog and get the location to
- save to.
- */
-
- StandardPutFile("\pPostScript® file to create:",
- "\pUntitled Print File", &putReply);
-
- require_action(putReply.sfGood, GotAnError, err = gxPrUserAbortErr;);
-
- /*
- If the user didn't cancel, save the file location, the
- print destination (to disk), the file format name, and
- the font inclusion info.
- */
-
- BlockMove(&putReply.sfFile, &fileLocInfo.fileSpec, sizeof(FSSpec));
- StoreJobCollectionItem(&fileLocInfo, sizeof(gxFileLocationInfo),
- gxFileLocationTag, gxPrintingTagID);
-
- destInfo.toFile = true;
- StoreJobCollectionItem(&destInfo, sizeof(gxFileDestinationInfo),
- gxFileDestinationTag, gxPrintingTagID);
-
- BlockMove("PostScript®", &destFFmt.fileFormatName[1], 11);
- destFFmt.fileFormatName[0] = 11;
- StoreJobCollectionItem(&destFFmt, sizeof(gxFileFormatInfo),
- gxFileFormatTag, gxPrintingTagID);
-
- fontsInfo.includeFonts = gxIncludeNoFonts;
- StoreJobCollectionItem(&fontsInfo, sizeof(gxFileFontsInfo),
- gxFileFontsTag, gxPrintingTagID);
- GotAnError:
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverPrValidate -
-
- This routine is a total override of the gxPrValidate message.
- In here, we set up our default settings if we have an
- uninitialized or unknown print record.
-
- WHY THIS IS IMPORTANT:
-
- If you don't override this message, the default PostScript
- implementation will validate your print records for you. If
- you're using a different wDev, then the default implementation
- will keep changing your print record as soon as it notices
- your wDev. You don't need to completely override this message,
- but if your wDev is different than the LaserWriter driver's
- you'll have to massage it before and after you forward the
- message.
-
- The implemenation below assumes that we've overriden
- gxPrintDefault so that our default print record is read in.
-
- ______________________________________________________________ */
-
- OSErr DriverPrValidate(THPrint printHdl, Boolean *changedPtr)
- {
- short deviceWord, version;
- Boolean changed = true;
- OSErr err = noErr;
-
- /*
- If the high byte of the wDev for our driver and this print
- record don't agree, call PrintDefault to load our default
- print record. Note that we don't check the version number
- here, but you may want to do that as well.
-
- If the caller didn't pass us nil, return a flag indicating
- whether or not we changed the print record.
- */
-
- deviceWord = (*printHdl)->prStl.wDev;
- version = (*printHdl)->iPrVersion;
-
- if ((deviceWord >> 8) != kDeviceByte)
- PrintDefault(printHdl);
- else
- changed = false;
-
- if (changedPtr != nil)
- *changedPtr = changed;
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- DriverPrintDefault -
-
- This routine is a total override of the gxPrintDefault message.
- In here, we copy our default settings into the passed print
- handle.
-
- WHY THIS IS IMPORTANT:
-
- You need to override this message so that your gxPrValidate
- override and other callers can get your driver's default print
- record when they need it. This is best handled as a total
- override, since the driver writer should specify what the
- driver's default values are.
-
- ______________________________________________________________ */
-
- OSErr DriverPrintDefault(THPrint printHdl)
- {
- OSErr err = noErr;
- short oldResFile;
- Handle defaultPrintRec;
-
- /*
- Save our old resource file, use our driver's resource file,
- and load our default 'PREC' resource. Copy that data into
- our print handle, release the resource, and restore the
- original resource file to the top of the chain before exiting.
- */
-
- oldResFile = CurResFile();
- UseResFile(GXGetMessageHandlerResFile());
-
- defaultPrintRec = GetResource('PREC', 0);
- require_action(defaultPrintRec, GetResource_Failed, err = resNotFound;);
-
- BlockMove(*defaultPrintRec, *printHdl, GetHandleSize(defaultPrintRec));
- ReleaseResource(defaultPrintRec);
-
- GetResource_Failed:
-
- UseResFile(oldResFile);
-
- return err;
- }
-
- /* ______________________________________________________________ */
-
- enum { // wdev
- kFontSubstitution = 0x0001,
- kPortrait = 0x0002,
- kGraphicSmoothing = 0x0004,
- kTextSmoothing = 0x0020
- };
-
- enum { // printX[0]
- kColorMode = 0x0008
- };
-
- enum { // printX[5]
- kInvertPage = 0x0001,
- kFlipPageHoriz = 0x0002,
- kFlipPageVert = 0x0004,
- kPreciseBitmap = 0x0010,
- kLargerPrintArea = 0x0020,
- kDownloadFonts = 0x0080,
- kPlus90 = 0x1000
- };
-
- /* ______________________________________________________________
-
- DriverConvertPrintRecordTo -
-
- This routine is a total override of the gxConvertPrintRecordTo
- message. In here, we translate the passed old-world print
- record into a universal print record. This routine is the
- opposite of DriverConvertPrintRecordFrom.
-
- WHY THIS IS IMPORTANT:
-
- This is how we pass data between the old and new printing
- architectures. You normally totally override this message
- since you should be the authority on where your driver stores
- which settings.
-
- ______________________________________________________________ */
-
- OSErr DriverConvertPrintRecordTo(THPrint aPrintHdl)
- {
- gxUniversalPrintRecord *univRecPtr;
- TPrint *printRecPtr;
-
- /*
- This driver's print record already matches up pretty
- well to the universal print record. Only the fields
- below need to be mapped.
- */
-
- univRecPtr = *(gxUniversalPrintRecordHdl) aPrintHdl;
- printRecPtr = *aPrintHdl;
-
-
- /*
- We move the orientation, "print to file" and "manual feed"
- settings from their private locations to their universal
- locations. Note that we also update our devType, because
- universal print records always have $A9 in the high byte
- of their wDev.
- */
-
- univRecPtr->orientation = (printRecPtr->prStl.wDev & 0x2)? gxPortraitOrientation :gxLandscapeOrientation;
- univRecPtr->saveFile = (printRecPtr->prXInfo.bUlOffset == 0)? 0 :1;
-
- univRecPtr->feed = (printRecPtr->prStl.feed == 3)? gxManualFeed :gxAutoFeed;
- univRecPtr->devType = (univRecPtr->devType & 0xFF) | 0xA900;
- univRecPtr->coverPage = printRecPtr->prXInfo.iBandV;
-
- univRecPtr->options = 0;
-
- if (printRecPtr->prStl.wDev & kFontSubstitution)
- univRecPtr->options |= gxFontSubstitution; // font substitution
- if (printRecPtr->prStl.wDev & kGraphicSmoothing)
- univRecPtr->options |= gxGraphicSmoothing; // graphic smoothing (LW)
- if (printRecPtr->prStl.wDev & kTextSmoothing)
- univRecPtr->options |= gxTextSmoothing; // text smoothing (SC)
-
- if (printRecPtr->printX[0] & kColorMode)
- univRecPtr->options |= gxColorMode; // color printing
-
- if (printRecPtr->printX[5] & kInvertPage)
- univRecPtr->options |= gxInvertPage; // b/w invert image;
- if (printRecPtr->printX[5] & kFlipPageHoriz)
- univRecPtr->options |= gxFlipPageHoriz; // flip horizontal
- if (printRecPtr->printX[5] & kFlipPageVert)
- univRecPtr->options |= gxFlipPageVert; // flip vertical
- if (printRecPtr->printX[5] & kPreciseBitmap)
- univRecPtr->options |= gxPreciseBitmap; // tall adjusted (IW), precise bitmap (LW, SC)
- if (printRecPtr->printX[5] & kLargerPrintArea)
- univRecPtr->options |= gxBiggerPages; // no gaps (IW), larger print area (LW)
-
- if (false)
- univRecPtr->options |= gxBidirectional; // bidirectional printing
- if (false)
- univRecPtr->options |= gxUserFlag2; // user flag 2
-
- return noErr;
- }
-
-
- /* ______________________________________________________________
-
- DriverConvertPrintRecordFrom -
-
- This routine is a total override of the gxConvertPrintRecordFrom
- message. In here, we translate the passed universal print record
- into an old-world print record. This routine is the opposite of
- DriverConvertPrintRecordTo.
-
- WHY THIS IS IMPORTANT:
-
- This is how we pass data between the old and new printing
- architectures. You normally totally override this message
- since you should be the authority on where your driver stores
- which settings.
-
- ______________________________________________________________ */
-
- OSErr DriverConvertPrintRecordFrom(THPrint aPrintHdl)
- {
- gxUniversalPrintRecord *univRecPtr;
- TPrint *printRecPtr;
-
- /*
- This driver's print record already matches up pretty
- well to the universal print record. Only the fields
- below need to be mapped back to the old style print
- record.
- */
-
- univRecPtr = *(gxUniversalPrintRecordHdl) aPrintHdl;
- printRecPtr = *aPrintHdl;
-
- /*
- We move the orientation, "print to file" and "manual feed"
- settings from their universal locations to their private
- ones. Note that we also update our WDev, because
- universal print records always have $A9 in the high byte
- of their wDev, and we need our device ID there.
- */
-
- if (univRecPtr->orientation == gxPortraitOrientation)
- printRecPtr->prStl.wDev |= 0x2;
- else
- printRecPtr->prStl.wDev &= ~0x2;
-
- printRecPtr->prStl.feed = (univRecPtr->feed == gxManualFeed)? 3: 2;
- printRecPtr->prXInfo.bUlOffset = (univRecPtr->saveFile)? 1: 0;
-
- if (univRecPtr->options & gxFontSubstitution) // font substitution
- printRecPtr->prStl.wDev |= kFontSubstitution;
- if (univRecPtr->options & gxGraphicSmoothing) // graphic smoothing (LW)
- printRecPtr->prStl.wDev |= kGraphicSmoothing;
- if (univRecPtr->options & gxTextSmoothing) // text smoothing (SC)
- printRecPtr->prStl.wDev |= kTextSmoothing;
-
- printRecPtr->prStl.wDev = (printRecPtr->prStl.wDev & 0xFF) | (kDeviceByte << 8);
-
- if (univRecPtr->options & gxInvertPage) // b/w invert image;
- printRecPtr->printX[5] |= kInvertPage;
- if (univRecPtr->options & gxFlipPageHoriz) // flip horizontal
- printRecPtr->printX[5] |= kFlipPageHoriz;
- if (univRecPtr->options & gxFlipPageVert) // flip vertical
- printRecPtr->printX[5] |= kFlipPageVert;
- if (univRecPtr->options & gxPreciseBitmap) // tall adjusted (IW), precise bitmap (LW, SC)
- printRecPtr->printX[5] |= kPreciseBitmap;
- if (univRecPtr->options & gxBiggerPages) // no gaps (IW), larger print area (LW)
- printRecPtr->printX[5] |= kLargerPrintArea;
-
- printRecPtr->prXInfo.iBandV = univRecPtr->coverPage;
-
- /*
- explicitly need to set fields in prXinfo part of univ to 0 or they will affect printrec,
- the following assumes that we don't ever care about whats in bPatScale, bUITThick, bUIOffset, etc
- */
- univRecPtr->orientation = 0; // so iDevBytes doesn't get set
- univRecPtr->qualityMode = 0;
- univRecPtr->coverPage = 0; // so iBands doesn't gets set to 1
- univRecPtr->firstTray = 1; // as thats what LW does.
-
- return noErr;
- }
-
-
- /* ______________________________________________________________
-
- StoreJobCollectionItem -
-
- This routine is a generic routine that stores a collection
- item in the current job's collection. If the item already
- exists it is replaced.
-
- WHY THIS IS IMPORTANT:
-
- It's not. This is just a utility routine.
-
- ______________________________________________________________ */
-
- OSErr StoreJobCollectionItem(void *collectItem, long collectSize,
- OSType collectType, long collectID)
- {
- OSErr err;
- Collection jobCollection;
- long index, itemSize, attributes;
-
- /*
- Get the job collection and add the new data. If the item
- already exists and is locked, replace it.
- */
-
- jobCollection = GXGetJobCollection(GXGetJob());
-
- err = AddCollectionItem(jobCollection,
- collectType,
- collectID,
- collectSize,
- collectItem);
-
- if (err == collectionItemLockedErr)
- {
- err = GetCollectionItemInfo(jobCollection,
- collectType,
- collectID,
- &index,
- &itemSize,
- &attributes);
- if (!err)
- err = ReplaceIndexedCollectionItem(jobCollection,
- index,
- collectSize,
- collectItem);
- }
-
- return err;
- }
-
-
- /* ______________________________________________________________
-
- ToggleControl -
-
- This routine toggles a control on or off. It's useful for
- controls like checkboxes or radio buttons, which can only have
- a value of 0 or 1. The function takes a "void **" so that we
- don't have to typecast the handle returned from GetDItem before
- calling this routine.
-
- WHY THIS IS IMPORTANT:
-
- It's not. This is just a utility routine.
-
- ______________________________________________________________ */
-
- void ToggleControl(void **itemH)
- {
- short ctlVal = GetCtlValue((ControlHandle) itemH);
-
- ctlVal = (ctlVal == 1)? 0: 1;
- SetCtlValue((ControlHandle) itemH, ctlVal);
- }
-
-
- /* ______________________________________________________________
-
- SetTheControlValue -
-
- This routine sets the passed control's value, if necessary. It
- will not set a control to a value it's already set to, and that
- avoids flashing. The function takes a "void **" so that we
- don't have to typecast the handle returned from GetDItem before
- calling this routine.
-
- WHY THIS IS IMPORTANT:
-
- It's not. This is just a utility routine.
-
- ______________________________________________________________ */
-
- void SetTheControlValue(void **itemH, short desiredValue)
- {
- short ctlVal = GetCtlValue((ControlHandle) itemH);
-
- if (ctlVal != desiredValue)
- SetCtlValue((ControlHandle) itemH, desiredValue);
- }
-